package com.tangyuan.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tangyuan.common.algorithm.Pearson;
import com.tangyuan.dto.UserActionByUserIdDto;
import com.tangyuan.feignapis.user.IUserActionFeignClient;
import com.tangyuan.mapper.UserCoordination2Mapper;
import com.tangyuan.model.UserAction;
import com.tangyuan.model.UserCoordination2;
import com.tangyuan.model.UserLike;
import com.tangyuan.service.UserCoordination2Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 小梁
 * @since 2020-12-03
 */
@Slf4j
@Service
public class UserCoordination2ServiceImpl extends ServiceImpl<UserCoordination2Mapper, UserCoordination2> implements UserCoordination2Service {

    @Autowired
    IUserActionFeignClient userActionFeignClient;

    @Override
    public List<UserCoordination2> getUserCoordination2ByUserId1(List<Long> userIds) {
        if(CollectionUtils.isEmpty(userIds)){
            return new ArrayList<>();
        }
        return baseMapper.getUserCoordination2ByUserId1(userIds);
    }

    @Override
    public List<UserCoordination2> getUserCoordination2PageByUserId1(Long userId) {
        if(userId == null || userId == 0){
            return new ArrayList<>();
        }
        return baseMapper.getUserCoordination2PageByUserId1(userId);
    }

    /**
     * 根据用户Id 查询与自己相似的三个用户查看过的视频id (过滤当前用户看过的视频)
     *相邻用户的高分电影id列表(user_coordination2表)
     * @param userId 用户Id
     * @return List<Long>
     */
    @Override
    public List<Long> getMovieIdList(Long userId) {
        //总推荐
        if(userId == null){
            return new ArrayList<>();
        }
        List<UserCoordination2> records = this.getUserCoordination2PageByUserId1(userId);
        if(CollectionUtil.isEmpty(records)){
            return new ArrayList<>();
        }
        List<Long> list = new ArrayList<>();
        list.addAll(getResemblanceMovie(userId,records,0));
        list.addAll(getResemblanceMovie(userId,records,1));
        return list;
    }

    /**
     * 查找用户的正反相关用户查看过的视频
     * @param userId 用户
     * @param records UserCoordination2表数据
     * @param type 0为正相关，1为负相关
     * @return
     */
    private List<Long> getResemblanceMovie(Long userId,List<UserCoordination2> records,Integer type) {
        List<Long> collect = records.stream().filter(item -> item.getType().equals(type)).map(UserCoordination2::getUserId2).collect(Collectors.toList());
        if(CollectionUtil.isEmpty(collect)){
            return new ArrayList<>();
        }
        UserActionByUserIdDto userActionByUserIdDto = new UserActionByUserIdDto();
        userActionByUserIdDto.setUserId(userId);
        userActionByUserIdDto.setUserIds(collect);

        if(type.equals(0)){
            userActionByUserIdDto.setJustScore(new BigDecimal("2.6"));
            userActionByUserIdDto.setLoseScore(null);
            return userActionFeignClient.getUserActionByUserIdDto(userActionByUserIdDto);
        }else {
            userActionByUserIdDto.setJustScore(null);
            userActionByUserIdDto.setLoseScore(new BigDecimal("2.2"));
            return userActionFeignClient.getUserActionByUserIdDto(userActionByUserIdDto);
        }
    }

    @Override
    public void saveUserCoordination2(List<UserAction> userActions,List<UserLike> likes) {
        long l = System.currentTimeMillis();
        //昨日有活跃的用户
        List<Long> userIds = likes.stream().map(UserLike::getUserId).collect(Collectors.toList());
        //获取已保存的数据
        List<UserCoordination2> coordinationList = this.getUserCoordination2ByUserId1(userIds);
        if(CollectionUtils.isEmpty(coordinationList)){
            coordinationList = new ArrayList<>();
        }
        List<UserCoordination2> saveCoordination2List =  new ArrayList<>();
        int i = 1;
        for (UserLike like : likes) {
            List<UserAction> userActionList = userActions.stream().filter(userAction -> Objects.equals(userAction.getUserId(), like.getUserId())).collect(Collectors.toList());
            //已经保存的数据不在循环 例如: id 1,2,3 第二次循环时从2开始
            List<UserLike> userLikes = likes.subList(i, likes.size());
            i++;
            for (UserLike userLike : userLikes) {
                if (Objects.equals(like.getUserId(), userLike.getUserId())) {
                    continue;
                }
                //查看库中是否有对应数据
                UserCoordination2 coordination2 = null;
                List<UserCoordination2> coordination = coordinationList.stream().filter(
                                coo ->  coo.getUserId2().equals(like.getUserId())
                                        && coo.getUserId1().equals(userLike.getUserId()))
                        .collect(Collectors.toList());

                if(!CollectionUtils.isEmpty(coordination)){
                    coordination2 = coordination.get(0);
                }else {
                    coordination2 = new UserCoordination2();
                    coordination2.setUserId1(userLike.getUserId());
                    coordination2.setUserId2(like.getUserId());
                }
                double y = Pearson.getPearsonCorrelationScore(userActions, userActionList);
                coordination2.setType(0);
                if (y < 0) {
                    y = -y;
                    // 负相关标志为1
                    coordination2.setType(1);
                }
                coordination2.setDistance(y);
                saveCoordination2List.add(coordination2);
            }
        }
        this.saveOrUpdateBatch(saveCoordination2List);
        log.info("saveUserCoordination2:执行时间"+(System.currentTimeMillis() - l));
    }


    /**
     * 根据用户查询UserCoordination2表 (表设计 userId2 小于 userId1)
     * @param userId1 userId1
     * @param userId2 userId2
     * @return UserCoordination2表
     */
    @Override
    public UserCoordination2 getUserCoordination2(Long userId1, Long userId2) {
        if(userId1 == null || userId1 == 0 || userId2 == null || userId2 == 0){
            return null;
        }
        if(userId2 > userId1){
            return baseMapper.getUserCoordination2(userId2,userId1);
        }
        return baseMapper.getUserCoordination2(userId1,userId2);
    }
}
